

#include "ringbuff.h"
#include "common.h"

ringbuff_t *ringbuff_create(int item_size, int count)
{
    ringbuff_t *ringbuff;
    ringbuff = MEM_MALLOC(sizeof(ringbuff_t));
    if(ringbuff == NULL){
        debug_error("There is not enough space to allocate ringbuff struct");
        goto err;
    }

    uint8_t *ptr;
    int size;
    size = item_size * count;
    ptr = MEM_MALLOC(size);
    if(ptr == NULL){
        debug_error("There is not enough space to allocate ringbuff addr space");
        goto err;
    }

    ringbuff_init(ringbuff, ptr, size, item_size);
    return ringbuff;
err:
    if(ptr != NULL){
        MEM_FREE(ptr);
        ptr = NULL;
    }

    if(ringbuff != NULL){
        MEM_FREE(ringbuff);
        ringbuff = NULL;
    }

    return NULL;
}

void ringbuff_destroy(ringbuff_t *ringbuff)
{
    MEM_FREE(ringbuff->addr);
    ringbuff->addr = NULL;
    MEM_FREE(ringbuff);
    ringbuff = NULL;
}

void ringbuff_init(ringbuff_t *ringbuff, void *addr, uint32_t size, int item_size)
{
    ASSERT_NULL(ringbuff);

    ringbuff->addr = addr;
    ringbuff->buff_size = size;
    ringbuff->remin = size;
    ringbuff->read_idx = 0;
    ringbuff->write_idx = 0;

    ringbuff->item_size = item_size;
}

inline void ringbuff_clear(ringbuff_t *ringbuff)
{
    ringbuff->read_idx = ringbuff->write_idx = 0;
    ringbuff->remin = ringbuff->buff_size;
}

inline bool ringbuff_is_full(const ringbuff_t *ringbuff)
{
    return (ringbuff->remin < ringbuff->item_size) ? true : false;
}

inline bool ringbuff_push(ringbuff_t *ringbuff, void *push)
{
    if(ringbuff_is_full(ringbuff)){
        return false;
    }
    for(uint32_t i = 0; i < ringbuff->item_size; i++){
        *((uint8_t *)ringbuff->addr + ringbuff->write_idx) = *(uint8_t*)push++;
        ringbuff->write_idx = (ringbuff->write_idx + 1)%ringbuff->buff_size;
    }
    rt_enter_critical();
    ringbuff->remin -= ringbuff->item_size;
    rt_exit_critical();
    return true;
}

bool ringbuff_pop(ringbuff_t *ringbuff, void *save)
{
    if(ringbuff_is_empty(ringbuff) == true){
        return false;
    }
    for(uint32_t i = 0; i < ringbuff->item_size; i++){
        *((uint8_t *)save++) = *((uint8_t *)ringbuff->addr + ringbuff->read_idx);
        ringbuff->read_idx = (ringbuff->read_idx + 1)%ringbuff->buff_size;
    }
    rt_enter_critical();
    ringbuff->remin += ringbuff->item_size;
    rt_exit_critical();
    //rt_kprintf("pop task: %d\r\n", (ringbuff->read_idx)/8);
    return true;
}

bool ringbuff_show(ringbuff_t *ringbuff, void *save, uint32_t offset)
{
    if(ringbuff_is_empty(ringbuff) == true){
        return false;
    }
    uint32_t idx = (ringbuff->read_idx + offset)%ringbuff->buff_size;

    for(uint32_t i = 0; i < ringbuff->item_size; i++){
        *((uint8_t *)save++) = *((uint8_t *)ringbuff->addr + idx);
        idx = (idx + 1)%ringbuff->buff_size;
    }

    return true;
}

inline bool ringbuff_is_empty(const ringbuff_t *ringbuff)
{
    return (ringbuff->remin == ringbuff->buff_size)? true: false;
}

inline int ringbuff_used_count(const ringbuff_t *ringbuff)
{
    return (ringbuff->buff_size - ringbuff->remin)/ringbuff->item_size;
}

int ringbuff_remin(const ringbuff_t *ringbuff)
{
    return ringbuff->remin/ringbuff->item_size;
}


